package com.bidevalution.business.factory;

import com.alibaba.dubbo.common.json.JSON;
import com.bidevalution.business.common.RedisKeys;
import com.bidevalution.business.exception.CheckException;
import com.bidevalution.business.service.BeSectionExpertInfoService;
import com.bidevalution.business.service.BeSectionWarnMsgService;
import com.bidevalution.business.vo.CheckJobVo;
import com.bidevalution.dao.entity.BeSectionExpertInfo;
import com.bidevalution.dao.entity.BeSectionWarnMsg;
import com.bidevalution.dao.entity.CheckJob;
import com.bidevalution.dao.enums.CheckJobParamsEnum;
import com.qtp.core.redis.RedisUtil;
import com.qtp.core.util.GsonUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @version 1.6
 * @author whc
 * @修改 ZTKP-4025，增加专家确认无误缓存
 */
/**
 * job检查类, 所有job检查需要继承该类，方便后期维护,
 * check 可以重载设计，但理论上说是一个足够
 * 只有有检测不通过直接抛出CheckException，
 * 需要提醒，方法实现内各自实现自己部分的逻辑
 * whc
 *
 */
@Log4j2
@Component
public class CheckJobBase {
    private static CheckJobBase checkJobBase;
    @Autowired
    private BeSectionWarnMsgService beSectionWarnMsgService;
    @Autowired
    private BeSectionExpertInfoService beSectionExpertInfoService;

    /**
     * 初始化当前类
     */
    @PostConstruct
    public void init() {
        checkJobBase = this;
    }
    /**
     * 外部流程调用的基本检查
     * @param checkJob
     * @throws CheckException
     * @throws Exception
     */
    public void baseCheck(CheckJob checkJob) throws CheckException,Exception {
        String sectionId = checkJob.getSectionId();
        // 查找出来所有的专家
        List<BeSectionExpertInfo> sectionExperts = checkJobBase.beSectionExpertInfoService.getExpertListBySectionId(sectionId);
        try{
            checkJob.setAllExperts(sectionExperts);
            this.check(checkJob);
        } catch (CheckException e) {
            boolean isWarning = saveWarnMsg(checkJob, e);
            if (isWarning) {
                log.error("LOG[]baseCheck_61[]{},error={}","异常日志", GsonUtil.toJsonWithGson(e));
                throw e;
            }
        } catch (Exception e) {
            throw e;
        }
    }

    private boolean saveWarnMsg(CheckJob checkJob, CheckException e) throws Exception {
        // 是否自动插入
        if (!e.isAutoInsert()) {
            return true;
        }

        Map<String, String> expertNameMap = new HashMap<>();
        for (BeSectionExpertInfo item: checkJob.getAllExperts()) {
            expertNameMap.put(item.getSeqId(), item.getLoginName());
        }

        // 处理异常数据 中的 JOSN 数据
        CheckJobVo checkJobVo = new CheckJobVo();
        checkJobVo.setExperTotal(e.getNotificationMap().size());

        for (Map.Entry<String, Object> item : e.getNotificationMap().entrySet()) {
            String expertId = item.getKey();
            String expertName = expertNameMap.get(expertId);
            Object details = item.getValue();
            checkJobVo.addDetails(expertId, expertName, details);
        }

        // 从缓存取出确认无误的专家
        String expertConfirmKey = RedisKeys.ExpertConfirm.name() + checkJob.getSectionStepId() + checkJob.getSubmitCode();
        Map<String, String> confirmExpertonMap = RedisUtil.getAllMap(expertConfirmKey);
        // 剔除已经确认无误的专家
        for (String confirmExpertonId:confirmExpertonMap.keySet()) {
            checkJobVo.removeDetails(confirmExpertonId);
        }
        // 都确认无误，无异常直接跳出
        if (checkJobVo.getFailureMap().size() ==0) {
            return false;
        }

        // 覆盖之前的信息
        checkJobBase.beSectionWarnMsgService.overdueMag(checkJob.getSectionStepId());
        // 插入通知数据到表
        for (String expertId: e.getNotificationMap().keySet()) {
            BeSectionWarnMsg beSectionWarnMsg = new BeSectionWarnMsg(checkJob);
            boolean isFailurer = checkJobVo.getFailureMap().containsKey(expertId);
            // add Button
            addButton(checkJobVo, checkJob, CheckJobVo.ButtonEnum.Left);
            addButton(checkJobVo, checkJob, CheckJobVo.ButtonEnum.Right);

            // 存入
            checkJobVo.setMsg(isFailurer ? e.getErrorMsg() : e.getSuccessMsg());
            beSectionWarnMsg.setExpertId(expertId);
            beSectionWarnMsg.setMsgDetails(JSON.json(checkJobVo));

            checkJobBase.beSectionWarnMsgService.insertWarMsg(beSectionWarnMsg);
        }

        return true;
    }

    /**
     *
     * @param checkJobVo
     * @param checkJob
     * @param buttonEnum
     */
    private void addButton(CheckJobVo checkJobVo, CheckJob checkJob, CheckJobVo.ButtonEnum buttonEnum) {
        String nextActoin = null;
        String name = null;
        String hide = null;
        // 如果变多可以变成map
        switch (buttonEnum) {
            case Left:
                hide = checkJob.getParam(CheckJobParamsEnum.HideLeftBtn);
                name = checkJob.getParam(CheckJobParamsEnum.LeftBtnName);
                nextActoin = checkJob.getParam(CheckJobParamsEnum.LeftBtnAction);
                break;
            case Right:
                hide = checkJob.getParam(CheckJobParamsEnum.HideRightBtn);
                name = checkJob.getParam(CheckJobParamsEnum.RightBtnName);
                nextActoin = checkJob.getParam(CheckJobParamsEnum.RightBtnAction);
                break;
                default:
                    break;
        }
        checkJobVo.addBtton(buttonEnum, name, nextActoin, hide);
    }

    /**
     * 子类实现业务检查
     * @param checkJob
     * @throws CheckException
     * @throws Exception
     */
    public void check(CheckJob checkJob) throws CheckException,Exception {

    };
}
